<?php
/**
 * Base controller for AED (add - edit - delete) functionality. Operates a data from a database. Useful when building an administrative interface
 *
 * @author Konstantin Shamko <konstantin.shamko@gmail.com> 
 * @version 0.0.1
 * @copyright  Copyright (c) 2009 Konstantin Shamko
 * @category VaselinEngine
 * @package Bel Classes
 * @license  New BSD License
 * 
 */
abstract class Bel_Controller_Aed extends Bel_Controller{
	/**
	 * Name of the grid template
	 *
	 * @var string
	 */	
	protected $_grid_template = 'grids/default.tpl';
	
	/**
	 * Template with add/edit form
	 *
	 * @var string
	 */	
	protected $_form_template = 'forms/default.tpl';
		
	/**
	 * Name of a form to add/edit entry 
	 *
	 * @var string
	 */
	protected $_formname;
	
	/**
	 * Action that shows data grid. Sets automatically, but could be changed
	 *
	 * @var string
	 */
	protected $_index_action;
		
	/**
	 * URL that will bring user to add/edit form. Sets automatically, but could be changed
	 *
	 * @var string
	 */
	protected $_form_action;	
	
	/**
	 * URL to delete an entry from a DB. Sets automatically, but could be changed
	 * 
	 * @var string
	 */
	protected $_delete_action;	
	
	/**
	 * Form action to add/edit an entry. Sets automatically, but could be changed
	 *
	 * @var string
	 */
	protected $_modify_action;
	
	/**
	 * Model object to operate with.
	 *
	 * @var Bel_Model_Abstaract
	 */
	protected $_model;	
	
	/**
	 * Zend_Session object to store data from form to show populated form in case of errors during submition 
	 *
	 * @var Zend_Session_Namespace
	 */
	protected $_formdata;
	
	/**
	 * Grid object. Needed to build data grids
	 *
	 * @var Bel_Grid
	 */
	protected $_grid;
	
	/**
	 * Quantity of entries to show in grid
	 *
	 * @var int
	 */
	protected $_items_on_page = 0;	
	
	/**
	 * Db editable/deletable entry 
	 *
	 * @var array
	 */	
	protected $_current_entry;
	
	/**
	 * Array with added entry primary key name and value. Use in _afterModify() method
	 *
	 * @var array
	 */
	protected $_added_entry;	
		
	/**
	 * Object initialization
	 *
	 * @return void
	 */
	public function init() {
		parent::init ();
		$controller = $this->_request->getControllerName ();
		$module = $this->_request->getModuleName ();

		$this->_index_action = $module . '/' . $controller . '/index';
		$this->_form_action = $module . '/' . $controller . '/form';
		$this->_delete_action = $module . '/' . $controller . '/delete';
		$this->_modify_action = $module . '/' . $controller . '/modify';
		
		$this->_formdata = new Zend_Session_Namespace ( 'formdata' );
		
		if (isset ( $this->_formdata->request )) {	
			$this->view->assign('messages',$this->_messages->getMessages());
		}
	}	
	
	/**
	 * Index action. Displays a data grid
	 * 
	 * @return void
	 */  
    public function indexAction(){
    	$this->_grid = new Bel_Grid();
    	
    	$filter=$this->_request->getParam('filter');
		
		if(isset($filter)){
			$where = $this->_buildWhere($filter);
		}else{
			$where = NULL;
		}
		
		$sortby = $this->_request->getParam('sortby');
		$order = $this->_request->getParam('order');	 
		
		if(!isset($sortby) || $sortby==null){
			$sortorder = NULL;
		}else{
			$sortorder = $sortby.' '.$order;
		}    	
	
    	$this->_model->setItemsOnPage($this->_items_on_page);
    	$dataset = $this->_model->getAll($where,$sortorder,$this->_request->getParam('page'));

    	$this->_grid
    		->setEditAction ( $this->_form_action )
			->setDelAction ( $this->_delete_action )
			->setAddAction ( $this->_form_action );
		
    	$this->view->assign('grid',$this->_grid->buildGrid($this->_formname,$dataset));
    	$this->view->assign('paging',$this->_model->getPaging($this->_index_action.'/?page='));
		$this->view->display ( $this->_grid_template );
    }
    
    /**
     * Displays add or edit entry form
     */
    public function formAction(){    	    	
    	
    	$form = new Bel_Forms_Builder ( $this->_formname, $this->_modify_action);
    	$primary_key = $this->_setCurrentEntry();
    	
    	$this->_prepareForm($form);    	 
	
		if($primary_key['value']){ //edit form generation
			$form->addElement ( 'hidden', $primary_key['key'] );

			if($this->_current_entry){ 
				$form->populateForm($this->_current_entry);
				
				if (isset ( $this->_formdata->request )) {				
					$this->_formdata->unsetAll ();
				}
			}else{ //if there is nothing to edit
				$this->_messages->setMessage ( 'There is no entry to edit', 'error' );
				$this->_redirect ( $this->_index_action );				
			}
		}else{ //add form generation
			if (isset ( $this->_formdata->request )) {				
				$form->populateForm ( $this->_formdata->request );
				$this->_formdata->unsetAll ();
			}
		}
		
		$this->_predisplayForm($form);
				
		$this->view->assign ( 'form', $form );
		$this->view->display ( $this->_form_template );		
    }    
    
    /**
     * Edits or adds entry into db
     */
    public function modifyAction(){	
    	$primary_key = $this->_setCurrentEntry();

    			
		if ($this->_validator->validate ( $this->_formname, $this->_request->getParams () )) {			
			$this->_beforeModify();
			
			if($primary_key['value']){
				$this->_model->updateEntry ( $this->_request->getParams () );
				$this->_messages->setMessage('Entry has been updated');
				$this->_index_action = $this->_index_action . '/' . $primary_key['key'] . '/' . $primary_key['value'];									
			}else{
				$id = $this->_model->addEntry ( $this->_request->getParams () );
				$this->_messages->setMessage('Entry has been added');
				$this->_index_action = $this->_index_action . '/' . $primary_key['key'] . '/' . $id;
				$this->_added_entry = array('key'=>$primary_key['key'],'value'=>$id);
			}
			
			$this->_afterModify();			
			$this->_redirect ($this->_index_action);
		} else {
			foreach ( $this->_validator->getErrors () as $field=>$error ) {
				$this->_messages->setMessage ( $error, 'error' , $field);
			}
			$this->_formdata->request = $this->_request->getParams ();
			$this->_redirect ( $this->_form_action . '/' . $primary_key['key'] . '/' . $primary_key['value']);
		}
    }	
    
	/**
	 * Action to delete entry from a DB
	 *
	 */
	public function deleteAction() {		
		$primary_key = $this->_setCurrentEntry();		
		$this->_beforeDelete();
		$this->_model->deleteEntryById ( $primary_key['value'] );
		$this->_afterDelete();
		$this->_redirect ( $this->_index_action );
	}	
	
    /**
     * Returns model object
     * 
     * @return object
     */
    public function getModel(){
        return $this->_model;
    }	
    
	/**
	 * Method to be able to add/delete/modify form fields dynamically.$this->_current_entry variable is available in this method. 
	 * This variable contains array with edited data. It's available during edit (NOT ADD!!!) procedure.
	 */
	protected function _prepareForm(Bel_Forms_Builder $form)
	{}	
	
	/**
	 * Method to be able to add/delete/modify form fields dynamically before form displaying.$this->_current_entry variable is available in this method. 
	 * This variable contains array with edited data. It's available during edit (NOT ADD!!!) procedure.
	 */
	protected function _predisplayForm(Bel_Forms_Builder $form)
	{}	
	
	/**
	 * Method that runs before modify action. $this->_current_entry variable is available in this method. 
	 * This variable contains array with edited data. It's available during edit (NOT ADD!!!) procedure.
	 */
	protected function _beforeModify()
	{}
	
	/**
	 * Method that runs after modify action. $this->_current_entry variable is available in this method. 
	 * This variable contains array with edited data. It's available during edit (NOT ADD!!!) procedure.
	 */
	protected function _afterModify()
	{}	
	
	/**
	 * Method that runs before delete action. $this->_current_entry variable is available in this method. 
	 * This variable contains array with deleted data.
	 */
	protected function _beforeDelete()
	{}
	
	/**
	 * Method that runs after delete action. $this->_current_entry variable is available in this method. 
	 * This variable contains array with deleted data.
	 */
	protected function _afterDelete()
	{}	
	
	/**
	 * In form/modify/delete actions saves entry data into class variable. 
	 *
	 * @return array - data about entrie's primary key name and value
	 */
	private function _setCurrentEntry(){
		$id_col = $this->_model->getIdCol ();
		$id = $this->_request->getParam ( $id_col );
		
		if($id){
			$this->_current_entry = $this->_model->getEntryById ( $id );		
		
			if($this->_current_entry && !is_array($this->_current_entry)){
				$this->_current_entry = $this->_current_entry->toArray();
			}
		}	
		return array('key'=>$id_col,'value'=>$id);
	}	
	
	/**
	 * Builds where clause to filter data sets
	 *
	 * @param array $filter - associative array (key - name of a table field, value - field value)
	 * @return array
	 */
	private function _buildWhere($filter) {
		$where = array ();
		
		foreach ( $filter as $key => $val ) {
			if (isset ( $val ) && $val != '') {
				$where [] = new Zend_Db_Expr ( $key . ' LIKE \'%' . $val . '%\'' );
			}
		}
		
		if (count ( $where )) {
			return implode ( ' AND ', $where );
		} else {
			return NULL;
		}
	}	
}